<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="mHl9F" id="mHl9F"><span data-lake-id="u85934d7f" id="u85934d7f">典型回答</span></h1>
  <p data-lake-id="u42f17719" id="u42f17719"><span data-lake-id="uc65db179" id="uc65db179"><br>
    在Java中，我们自己想要判断线程是否存活，可以通过Thread下的isAlive()方法：</span></p>
  <p data-lake-id="uf1c692d7" id="uf1c692d7"><br></p>
  <pre lang="java"><code>
public class Test{

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -&gt; {
            System.out.println("t1 begin");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
            System.out.println("t1 end");
        });
        t1.start();
        System.out.println("t1.isAlive()="+t1.isAlive());
        t1.join();
        System.out.println("t1.isAlive()="+t1.isAlive());
    }
}
</code></pre>
  <p data-lake-id="u97289452" id="u97289452"><br></p>
  <p data-lake-id="u81be9b5e" id="u81be9b5e"><span data-lake-id="u95c24f4e" id="u95c24f4e">运行结果：</span></p>
  <p data-lake-id="u642bc7c2" id="u642bc7c2"><br></p>
  <pre lang="java"><code>
t1 begin
t1.isAlive()=true
t1 end
t1.isAlive()=false
</code></pre>
  <p data-lake-id="u5555ef98" id="u5555ef98"><br></p>
  <p data-lake-id="uf6104a85" id="uf6104a85"><span data-lake-id="u6cb2872c" id="u6cb2872c">但是事情并没有这么简单，先来看一下以下代码执行后t1的isAlive()方法返回：</span></p>
  <p data-lake-id="udb791b29" id="udb791b29"><br></p>
  <pre lang="java"><code>
public class Test{
    public static void main(String[] args) {
        Thread t1 = new Thread(() -&gt; {
            System.out.println("t1 begin");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
            System.out.println("t1 end");
        });
        Thread t2 = new Thread(() -&gt; {
            synchronized (t1) {
                System.out.println("t2 begin");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                }
                System.out.println("t2 end");
                System.out.println("t1 isAlive:" + t1.isAlive());
            }

        });
        t1.start();
        t2.start();
    }
}
</code></pre>
  <p data-lake-id="u2285968f" id="u2285968f"><br></p>
  <p data-lake-id="u5e919d2d" id="u5e919d2d"><span data-lake-id="u9dd5ce55" id="u9dd5ce55">运行结果：</span></p>
  <p data-lake-id="ufdf09ca8" id="ufdf09ca8"><br></p>
  <pre lang="java"><code>
t2 begin
t1 begin
t1 end
t2 end
t1 isAlive:true
</code></pre>
  <p data-lake-id="u71ef7979" id="u71ef7979"><br></p>
  <p data-lake-id="u2720f773" id="u2720f773"><span data-lake-id="u9975abf9" id="u9975abf9">可以看到t1已经结束了，但t1的isAlive()方法返回的是true。</span></p>
  <p data-lake-id="uc989e8fa" id="uc989e8fa"><span data-lake-id="u2fc0a3dc" id="u2fc0a3dc"><br></span><strong><span data-lake-id="uf104ce74" id="uf104ce74">产生这个现象的原因是isAlive()需要拿到当前对象的锁，注意上面代码中t2里对t1对象进行了synchronized，即t1线程在结束时需要修改自己的状态，而t1的被t2锁住，所以无法修改状态，导致isAlive()返回true。</span></strong></p>
  <p data-lake-id="ubc4aeac4" id="ubc4aeac4"><span data-lake-id="u80ef8d89" id="u80ef8d89"><br></span><span data-lake-id="ud59f7874" id="ud59f7874">上述具体原因，我们可以看java.lang.Thread.isAlive()方法的实现。</span></p>
  <p data-lake-id="u512095c3" id="u512095c3"><br></p>
  <pre lang="java"><code>
 public final native boolean isAlive();
</code></pre>
  <p data-lake-id="u8c33a584" id="u8c33a584"><br></p>
  <p data-lake-id="uda12c7a5" id="uda12c7a5"><span data-lake-id="ufeef9f27" id="ufeef9f27">可以看到这是个本地方法，对应到jdk源码中</span><code data-lake-id="ua0db7315" id="ua0db7315"><span data-lake-id="u9117008d" id="u9117008d">java_lang_Thread::is_alive</span></code><span data-lake-id="u1e230622" id="u1e230622">方法调用。其底层实现是取当前线程对象中_eetop_offset的值。不为空则返回true。</span></p>
  <p data-lake-id="u3c31a443" id="u3c31a443"><br></p>
  <pre lang="java"><code>
bool java_lang_Thread::is_alive(oop java_thread) {
  JavaThread* thr = java_lang_Thread::thread(java_thread);
  return (thr != NULL);
}
JavaThread* java_lang_Thread::thread(oop java_thread) {
  return (JavaThread*)java_thread-&gt;address_field(_eetop_offset);
}
</code></pre>
  <p data-lake-id="u323c937f" id="u323c937f"><br></p>
  <p data-lake-id="ud708a2d3" id="ud708a2d3"><span data-lake-id="ubb9ca052" id="ubb9ca052">_eetop_offset会在调用java.lang.Thread.start()方法时，在jdk源码中，通过</span><code data-lake-id="u8df39283" id="u8df39283"><span data-lake-id="ue30ef868" id="ue30ef868">native_thread-&gt;prepare(jthread)</span></code><span data-lake-id="uca81dd80" id="uca81dd80">的prepare方法设置为当前线程对象</span></p>
  <p data-lake-id="u1abdcd7d" id="u1abdcd7d"><br></p>
  <pre lang="java"><code>
void JavaThread::prepare(jobject jni_thread, ThreadPriority prio) {
  ... //此处缩略其他无关代码
  java_lang_Thread::set_thread(thread_oop(), this);//thread_oop()返回了jdk包装好的当前线程oop对象，this传入当前线程对象的地址
 ... //此处缩略其他无关代码
}
void java_lang_Thread::set_thread(oop java_thread, JavaThread* thread) {
  //设置_eetop_offset值为当前线程对象的地址
  java_thread-&gt;address_field_put(_eetop_offset, (address)thread); 
  
}
</code></pre>
  <p data-lake-id="u66e1d0aa" id="u66e1d0aa"><br></p>
  <p data-lake-id="uc29bd954" id="uc29bd954"><span data-lake-id="uf3ee8dc9" id="uf3ee8dc9">java线程结束时，jvm会调用</span><code data-lake-id="uaca12ee1" id="uaca12ee1"><span data-lake-id="u514107d6" id="u514107d6">JavaThread::exit</span></code><span data-lake-id="ubb2208e4" id="ubb2208e4">方法</span></p>
  <p data-lake-id="u9c474144" id="u9c474144"><br></p>
  <pre lang="java"><code>
void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
  ... //此处缩略其他无关代码
  ensure_join(this); //这里开始设置线程状态，包括设置_eetop_offset值为空
  ... //此处缩略其他无关代码
}

static void ensure_join(JavaThread* thread) {
  Handle threadObj(thread, thread-&gt;threadObj());
  assert(threadObj.not_null(), "java thread object must exist");
  ObjectLocker lock(threadObj, thread); //重点，拿到当前线程对象的锁
  thread-&gt;clear_pending_exception();
  java_lang_Thread::set_thread_status(threadObj(), java_lang_Thread::TERMINATED); //标记当前线程状态为终止
  java_lang_Thread::set_thread(threadObj(), NULL); //重点，_eetop_offset值为空
  lock.notify_all(thread);
  thread-&gt;clear_pending_exception();
}
</code></pre>
  <p data-lake-id="u84b0cba1" id="u84b0cba1"><br></p>
  <p data-lake-id="u25dee160" id="u25dee160"><code data-lake-id="u1a44cc40" id="u1a44cc40"><span data-lake-id="u6bb1d093" id="u6bb1d093">ObjectLocker</span></code><span data-lake-id="u488ee4e7" id="u488ee4e7">就是传说中的synchronized的实现，其构造函数如下</span></p>
  <p data-lake-id="u0277df54" id="u0277df54"><br></p>
  <pre lang="java"><code>
ObjectLocker::ObjectLocker(Handle obj, Thread* thread, bool doLock) {
  _dolock = doLock;
  _thread = thread;
  debug_only(if (StrictSafepointChecks) _thread-&gt;check_for_valid_safepoint_state(false);)
  _obj = obj; //拿到当前对象，在上面例子里，obj为t1

  if (_dolock) {
    TEVENT (ObjectLocker) ;
    ObjectSynchronizer::fast_enter(_obj, &amp;_lock, false, _thread); 
    //操作当前对象的对象头，执行synchronized的流程
    //由于t1的锁被t2持有，所以t1无法设置_eetop_offset值为空。自然isAlive()方法返回的是true，当然线程状态也无法修改为TERMINATED终止。
  }
}
</code></pre>
  <p data-lake-id="u7cc99b87" id="u7cc99b87"><br></p>
  <p data-lake-id="u2f419805" id="u2f419805"><strong><span data-lake-id="u55d8b577" id="u55d8b577">所以，在执行线程的退出过程中，需要拿到当前对象的锁之后才能设置_eetop_offset，上面的例子中，由于t1的锁被t2持有，所以t1无法设置_eetop_offset值为空。所以这时候isAlive()方法返回的就还是true，当然线程状态也无法修改为TERMINATED终止。</span></strong></p>
  <p data-lake-id="uaf7067f5" id="uaf7067f5"><br></p>
 </body>
</html>